package org.springframework;

import java.net.BindException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.ClientAbortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

import com.qiniu.common.QiniuException;
import com.zjdiepu.www.base.core.ApiResponse;
import com.zjdiepu.www.base.core.BaseException;
import com.zjdiepu.www.base.enums.type.ResultFlagType;
import com.zjdiepu.www.base.lang.HttpClientException;
import com.zjdiepu.www.common.consts.SystemConsts;
import com.zjdiepu.www.util.HttpUtil;
/**
 * 项目名称 dpqc-parent-manager-base <br/> 
 * 类名称 MyHandlerExceptionResolver <br/>  
 * 类描述 全局异常处理 <br/>    
 * 创建人 xiongxiaotun <br/> 
 * 创建时间 2017年4月9日 下午2:08:33  <br/>   
 * 修改人 xiongxiaotun <br/> 
 * 修改时间 2017年4月9日 下午2:08:33   <br/>  
 * 修改备注   <br/> 
 * @version V1.0   <br/>
 */
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
	private static final Logger logger = LoggerFactory.getLogger(MyHandlerExceptionResolver.class);
	
	@Override
	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
		if (ex == null) {
			return null;
		}
		boolean log = true;
		String mobileFlag = request.getHeader(SystemConsts.MOBILE_FLAG);
		if(ex instanceof ClientAbortException){ //请求主动断开（比如刷新页面等导致打断请求）
			log = false;
		} else if(ex instanceof BaseException) {
			BaseException bex = (BaseException)ex;
			if(ResultFlagType.LOGIN_TIMEOUT.getCode().toString().equals(bex.getErrorCode())){ //登录
				log = false;
			}
		}
		if(log) {
			String requestURI = request.getRequestURI();
			String contextPath = request.getContextPath();
			if(!requestURI.equals(contextPath + "/user/login")){ //登录POST
				logger.info("请求发生异常.requestURI:{}, mobileFlag : {} .异常栈:{}", requestURI, mobileFlag, ex);
			}
		}
		ModelAndView mv = null;
		int statusCode = 500;
		ApiResponse fail = null;
		if (ex instanceof NoSuchRequestHandlingMethodException) {
			statusCode = HttpServletResponse.SC_NOT_FOUND;
			fail = ApiResponse.fail(statusCode, "请求匹配失败");
		} else if (ex instanceof HttpRequestMethodNotSupportedException) {
			fail = ApiResponse.fail(ResultFlagType.HTTP_REQUEST_METHOD_NOT_SUPPORTED);
		} else if (ex instanceof HttpMediaTypeNotSupportedException) {
			fail = ApiResponse.fail(ResultFlagType.PARAM_TYPE_MISMATCH);
		} else if (ex instanceof HttpMediaTypeNotAcceptableException) {
			statusCode = HttpServletResponse.SC_NOT_ACCEPTABLE;
			fail = ApiResponse.fail(statusCode, "请求媒体类型不允许");
		} else if (ex instanceof MissingServletRequestParameterException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			fail = ApiResponse.fail(statusCode, "参数缺失");
		} else if (ex instanceof ServletRequestBindingException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			fail = ApiResponse.fail(statusCode, "参数绑定失败");
		} else if (ex instanceof ConversionNotSupportedException) {
			statusCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
			fail = ApiResponse.fail(statusCode, "参数转换不支持");
		} else if (ex instanceof TypeMismatchException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			fail = ApiResponse.fail(ResultFlagType.PARAM_TYPE_MISMATCH);
		} else if (ex instanceof HttpMessageNotReadableException) {
			HttpMessageNotReadableException e = (HttpMessageNotReadableException)ex;
			fail = ApiResponse.fail(ResultFlagType.HTTP_MESSAGE_NOT_READABLE.getCode(), null == e.getRootCause() ? e.getMessage() : e.getRootCause().getMessage());
		} else if (ex instanceof HttpMessageNotWritableException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			fail = ApiResponse.fail(statusCode, "消息内容不可写");
		} else if (ex instanceof MethodArgumentNotValidException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			MethodArgumentNotValidException e = (MethodArgumentNotValidException)ex;
			BindingResult bindingResult = e.getBindingResult();
			StringBuffer sb = new StringBuffer();

			for (FieldError fieldError : bindingResult.getFieldErrors()) {
				sb.append(fieldError.getDefaultMessage()).append(SystemConsts.NEW_LINE_CHARS);
			}
			String errorMesssage = sb.toString();
			if (errorMesssage.length() > 0) {
				errorMesssage = errorMesssage.substring(0, errorMesssage.length() - SystemConsts.NEW_LINE_CHARS.length());
			}
			fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID.getCode(), errorMesssage);
		} else if (ex instanceof MissingServletRequestPartException) {
			statusCode = HttpServletResponse.SC_BAD_REQUEST;
			fail = ApiResponse.fail(statusCode, "上传文件丢失");
		} else if (ex instanceof BindException) {
			fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID);
		} else if (ex instanceof NoHandlerFoundException) {
			statusCode = HttpServletResponse.SC_NOT_FOUND;
			fail = ApiResponse.fail(statusCode, "响应处理器匹配失败");
		} else if (ex instanceof BaseException) {
			BaseException e = (BaseException)ex;
			if(ResultFlagType.ACCESS_DENIED.getCode().toString().equals(e.getErrorCode())){
				fail =  ApiResponse.overdue(e.getErrorCode(), e.getErrorMsg());
			} else {
				fail =  ApiResponse.fail(e.getErrorCode(), e.getErrorMsg());
			}
		} else if (ex instanceof org.springframework.validation.BindException) {
			org.springframework.validation.BindException e = (org.springframework.validation.BindException)ex;
			BindingResult bindingResult =  e.getBindingResult();
			StringBuffer sb = new StringBuffer();

			for (FieldError fieldError : bindingResult.getFieldErrors()) {
				sb.append(fieldError.getDefaultMessage()).append(SystemConsts.NEW_LINE_CHARS);
			}
			String errorMesssage = sb.toString();
			if (errorMesssage.length() > 0) {
				errorMesssage = errorMesssage.substring(0, errorMesssage.length() - SystemConsts.NEW_LINE_CHARS.length());
			}
			fail = ApiResponse.fail(ResultFlagType.PARAM_INVALID.getCode(), errorMesssage);
		} else if (ex instanceof MultipartException) {
			fail = ApiResponse.fail(ResultFlagType.HTTP_UPLOAD_SIZE_EXCEEDED);
		} else if (ex instanceof QiniuException) {
			QiniuException e = (QiniuException)ex;
			fail = ApiResponse.fail(e.code(), e.error());
		} else if(ex instanceof HttpClientException){
			HttpClientException e = (HttpClientException)ex;
			fail = ApiResponse.fail(e.getHttpStatusCode(), e.getMessage());
		} else if (ex instanceof RuntimeException) {
			fail = ApiResponse.fail(ResultFlagType.HTTP_UNEXPECTED_SERVER_ERROR);
		} else {
			fail = ApiResponse.fail(ResultFlagType.FAIL);
		}
		try {
			if (HttpUtil.isAjax(request)) {
				mv = new ModelAndView(new MyJsonView());
			} else {
				mv = new ModelAndView(errorView);
			}
			mv.addObject(SystemConsts.ERROR_OBJECT, fail);
			return mv;
		} catch (Exception e) {
			logger.debug("异常处理出错了.", e);
		}
		return null;
	}
	
	/**
	 * 错误视图
	 */
	private String errorView;
	
	public String getErrorView() {
		return errorView;
	}

	public void setErrorView(String errorView) {
		this.errorView = errorView;
	}

}
